package com.google.code.opengw.http;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;

public class Response {
	private String protocol;
	private int responseCode;
	private String responseDetail;
	private List<HTTPHeader> httpHeaderList;
	private int contentLength;
	private boolean chunked;
	private boolean keepAlive;
	private ContentEncodingType encodingType;
	private byte[] content;

	public Response() {
		httpHeaderList = new ArrayList<HTTPHeader>();
		contentLength = -1;
	}
	
	public Response(String contentType, byte[] content){
		this.content = content;
		this.contentLength = content.length;
		protocol = HTTPConstants.HTTP_PROTOCOL;
		responseCode = HTTPConstants.CODE_200;
		responseDetail = HTTPConstants.CODE_200_DETAIL;
		httpHeaderList = new ArrayList<HTTPHeader>();
		httpHeaderList.add(new HTTPHeader("Content-Type", contentType));
		
	}
	
	public Response(int httpCode){
		 content = getErrorPage("" + httpCode).getBytes();
		 contentLength = content.length;
		 httpHeaderList = new ArrayList<HTTPHeader>();
		 httpHeaderList.add(new HTTPHeader("Content-Type", "text/html"));
		 httpHeaderList.add(new HTTPHeader("Server", "OpenGW"));
		 protocol = HTTPConstants.HTTP_PROTOCOL;
		 responseCode = httpCode;
		 responseDetail = HTTPConstants.getHTTPCodeMessage("" + httpCode);
	}
	
	public Response(int httpCode, int detailCode){
		content = getErrorPage("" + httpCode, "" + detailCode).getBytes();
		contentLength = content.length;
		httpHeaderList = new ArrayList<HTTPHeader>();
		httpHeaderList.add(new HTTPHeader("Content-Type", "text/html"));
		httpHeaderList.add(new HTTPHeader("Server", "OpenGW"));
		protocol = HTTPConstants.HTTP_PROTOCOL;
		responseCode = httpCode;
	 	responseDetail = HTTPConstants.getHTTPCodeMessage("" + httpCode);
	}

	private String getErrorPage(String httpCode){
		Formatter formatter = new Formatter();
		return formatter.format(HTTPConstants.HTTP_ERROR_PAGE_HTML, "HTTP Status " + httpCode + " - " + HTTPConstants.getHTTPCodeMessage(httpCode), "").toString();
	}
	
	private String getErrorPage(String httpCode, String detailCode){
		Formatter formatter = new Formatter();
		String s1 = "HTTP Status " + httpCode + " - " + HTTPConstants.getHTTPCodeMessage(httpCode);
		String s2 = HTTPConstants.getHTTPCodeMessage(detailCode);
		return formatter.format(HTTPConstants.HTTP_ERROR_PAGE_HTML, s1, s2).toString();
	}
	
	public String getHTTPHeaderString(boolean chunkAvailable) {
		StringBuilder httpResponse = new StringBuilder();
		httpResponse.append(protocol).append(" ").append(responseCode)
				.append(" ").append(responseDetail).append("\r\n");

		for (HTTPHeader header : httpHeaderList) {
			httpResponse.append(header.toHeaderLine());
		}
		if (!chunkAvailable && contentLength > 0) {
			httpResponse.append("Content-Length:").append(contentLength)
					.append("\r\n");
		} else if(chunkAvailable && chunked){
			httpResponse.append("Transfer-Encoding: chunked\r\n");
		}
		if (encodingType != null) {
			httpResponse.append("Content-Encoding:")
					.append(encodingType.name().toLowerCase()).append("\r\n");
		}
//		if(keepAlive){
//			httpResponse.append("Connection: Keep-Alive\r\n");
//		}

		httpResponse.append("\r\n");

		return httpResponse.toString();
	}

	public void addHeader(HTTPHeader header) {
		if (header.getName().equalsIgnoreCase("Transfer-Encoding")
				&& header.getValue().equalsIgnoreCase("chunked"))
			setChunked(true);
		else if (header.getName().equalsIgnoreCase("Content-Length"))
			setContentLength(Integer.parseInt(header.getValue()));
		else if (header.getName().equalsIgnoreCase("Content-Encoding"))
			setEncodingType(ContentEncodingType.valueOf(header.getValue()
					.toUpperCase()));
		else if(header.getName().equalsIgnoreCase("Connection") && header.getValue().equalsIgnoreCase("Keep-Alive")) 
			keepAlive = true;
		else
			httpHeaderList.add(header);
	}

	public byte[] getDecodedContent() throws IOException, DataFormatException {
		if (encodingType == ContentEncodingType.GZIP && content != null) {
			ByteArrayInputStream byteInpStream = new ByteArrayInputStream(
					content);
			GZIPInputStream gzipInputStream = new GZIPInputStream(byteInpStream);
			ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8196];
			int len = 0;
			while ((len = gzipInputStream.read(buffer)) != -1) {
				byteOutStream.write(buffer, 0, len);
			}
			gzipInputStream.close();
			byteInpStream.close();
			return byteOutStream.toByteArray();
		} else if (encodingType == ContentEncodingType.DEFLATE
				&& content != null) {
			Inflater decompresser = new Inflater();
			decompresser.setInput(content, 0, content.length);
			ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8196];
			int len = 0;
			while ((len = decompresser.inflate(buffer)) != -1) {
				byteOutStream.write(buffer, 0, len);
			}
			decompresser.end();
			return byteOutStream.toByteArray();
		} else {
			return content;
		}
	}

	public void setDecodedContent(byte[] decodedContent) throws IOException {
		if (encodingType == ContentEncodingType.GZIP && decodedContent != null) {
			ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
			GZIPOutputStream gzipInputStream = new GZIPOutputStream(
					byteOutStream);
			gzipInputStream.write(decodedContent);
			content = byteOutStream.toByteArray();
			contentLength = content.length;
		} else if (encodingType == ContentEncodingType.DEFLATE
				&& decodedContent != null) {
			Deflater compresser = new Deflater();
			compresser.setInput(decodedContent);
			ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8196];
			int len = 0;
			while ((len = compresser.deflate(buffer)) != -1) {
				byteOutStream.write(buffer, 0, len);
			}
			compresser.finish();
			content = byteOutStream.toByteArray();
			contentLength = content.length;
		} else {
			content = decodedContent;
			if (decodedContent != null) {
				contentLength = decodedContent.length;
			} else {
				contentLength = -1;
			}
		}
	}

	public int getResponseCode() {
		return responseCode;
	}

	public void setResponseCode(int responseCode) {
		this.responseCode = responseCode;
	}

	public List<HTTPHeader> getHttpHeaderList() {
		return httpHeaderList;
	}

	public void setHttpHeaderList(List<HTTPHeader> httpHeaderList) {
		this.httpHeaderList = httpHeaderList;
	}

	public int getContentLength() {
		return contentLength;
	}

	public void setContentLength(int contentLength) {
		this.contentLength = contentLength;
	}

	public ContentEncodingType getEncodingType() {
		return encodingType;
	}

	public void setEncodingType(ContentEncodingType encodingType) {
		this.encodingType = encodingType;
	}

	public byte[] getContent() {
		return content;
	}

	public void setContent(byte[] content) {
		this.content = content;
		if (content != null) {
			contentLength = content.length;
		}
	}

	public String getProtocol() {
		return protocol;
	}

	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	public String getResponseDetail() {
		return responseDetail;
	}

	public void setResponseDetail(String responseDetail) {
		this.responseDetail = responseDetail;
	}

	public boolean isChunked() {
		return chunked;
	}

	public void setChunked(boolean chunked) {
		this.chunked = chunked;
	}

	public boolean isKeepAlive() {
		return keepAlive;
	}

	public void setKeepAlive(boolean keepAlive) {
		this.keepAlive = keepAlive;
	}
	
	

}
